package gu.sql2java.json;

import java.lang.reflect.Type;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer;
import com.google.common.collect.Lists;

import gu.sql2java.BaseBean;
import gu.sql2java.Constant;
import gu.sql2java.RowMetaData;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.MoreObjects.firstNonNull;
import static gu.sql2java.utils.CaseSupport.isSnakecase;
import static gu.sql2java.utils.CaseSupport.toCamelcase;

/**
 * implementation of BaseBean class for 
 * FastJson {@link JavaBeanDeserializer},<br>
 * MAVEN dependencies:
 * <pre>
 *		&lt;dependency&gt;
 *			&lt;groupId&gt;com.alibaba&lt;/groupId&gt;
 *			&lt;artifactId&gt;fastjson&lt;/artifactId&gt;
 *			&lt;version&gt;${fastjson.version}&lt;/version&gt;
 *			&lt;scope&gt;provided&lt;/scope&gt;
 *		&lt;/dependency&gt;
 * </pre>
 * 
 * @author guyadong
 *
 */
public class FastjsonDeserializer extends JavaBeanDeserializer implements Constant {
	public FastjsonDeserializer(ParserConfig config, Class<? extends BaseBean> beanClass) {
		super(config, checkNotNull(beanClass,"beanClass is null"));
	}
	public FastjsonDeserializer(Class<? extends BaseBean> beanClass) {
		this(ParserConfig.global, beanClass);
	}
	@SuppressWarnings("unchecked")
	@Override
	public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
		/** deserialze to JSONObject */
		JSONObject json = (JSONObject)super.deserialze(parser, JSONObject.class, fieldName);
		// replace key to camel-case if snake-case
		for(String key:Lists.newArrayList(json.keySet()) ) {
			if(isSnakecase(key)) {
				String camelcase = toCamelcase(key);
				if(!json.containsKey(camelcase)) {
					json.put(camelcase, json.get(key));
					json.remove(key);
				}
			}
		}
		/** convert Map to target type based BaseBean  */
		try {
			BaseBean bean = (BaseBean) createInstance(json, parser.getConfig());
			bean.setNew(firstNonNull(json.getBoolean(FIELD_NEW), true));
			Integer modified = json.getInteger(FIELD_MODIFIED);
			Integer initialized = json.getInteger(FIELD_INITIALIZED);
			if(null != initialized){
				bean.setInitialized(initialized);
			}
			if(null != modified){
				bean.setModified(modified);
			}
			return (T) bean;
		} catch (Exception e) {
			throw new JSONException(e.getMessage(), e);
		}
	}

	/**
	 * define FASTJSON deserializer for all class derived from BaseBean using {@link ParserConfig#global} 
	 */
	public static void install() {
		install(ParserConfig.global);
	}
	/**
	 * define FASTJSON deserializer for all class derived from BaseBean  
	 * @param config using {@link ParserConfig#global} instead of {@code null} 
	 */
	public static void install(ParserConfig config) {
		for(RowMetaData metaData:RowMetaData.allMetaDataList()){
			ParserConfig.global.putDeserializer(
					metaData.beanType,
					new FastjsonDeserializer(firstNonNull(config,ParserConfig.global),metaData.beanType));
		}
	}

}
